<template>
  <div class="zeesuu-search-list">
    <!-- 搜索表单部分 -->
    <div class="search-box">
      <!-- 配置的组件 -->
      <div class="search-input-box">
        <!-- 自动分行 -->
        <el-row :gutter="20">
          <el-col
            v-for="(opt, index) in state.s_localOption"
            :key="index"
            :span="24 / (opt.col || itemPerRow)"
          >
            <!-- element的变化:el-date-picker变为YYYY-MM-DD且不在支持value-format -->
            <component
              :is="opt.type"
              :label="opt.label"
              :conf="opt.conf"
              :placeholder="opt.label"
              clearable
              :format="opt.type==='el-date-picker'?'YYYY-MM-DD HH:mm:ss':''"
              :type="opt.type==='el-date-picker'?'datetime':''"
              v-bind="opt.$attrs || {}"
              v-model="state.s_searchInfo[opt.name]"
            ></component>
          </el-col>
        </el-row>
      </div>

      <!-- 按钮布局 -->
      <div class="search-btn-box">
        <slot
          name="btn-before"
          class="btn-before"
          :selectedData="state.s_selectedData"
          :searchInfo="state.s_searchInfo"
        ></slot>
        <el-button
          type="primary"
          size="mini"
          @click="s_fetchData"
          v-if="state.s_localOption.length > 0"
          icon="el-icon-search"
        >
          查询
        </el-button>
        <el-button @click="s_resetSearchInfo" size="mini" v-if="state.s_localOption.length > 0">
          清空
        </el-button>
        <slot
          name="btn-after"
          class="btn-after"
          :selectedData="state.s_selectedData"
          :searchInfo="state.s_searchInfo"
        ></slot>
      </div>
    </div>
    <slot name="tab-before"></slot>

    <!-- 表格 -->
    <el-table
      :data="state.s_list"
      v-loading="s_pagination.loading"
      @selection-change="s_selectChange"
      size="mini"
      ref="searchTable"
      border
      :row-key="rowKey"
      v-bind="$attrs"
    >
      <slot :scope="state.s_list"></slot>
    </el-table>

    <!-- 翻页 总数不等于当前页面的数据长度 -->
    <el-pagination
      layout="total, sizes, prev, pager, next, jumper"
      @current-change="s_pageChange"
      @size-change="s_sizeChange"
      :page-sizes="[10, 50, 100]"
      :current-page="~~s_pagination.page + pageOffset"
      :page-size="s_pagination.size"
      :total="s_pagination.total"
    ></el-pagination>
  </div>
</template>

<script>
  import { computed, getCurrentInstance, onMounted, reactive, ref, watch } from 'vue';
  export default {
    props: {
      apiUrl: {
        type: String,
        default: '',
        required: true,
      },
      rowKey: {
        type: String,
        default: 'id',
      },
      option: {
        type: Array,
        default: () => [],
      },
      pagination: {
        type: Object,
        default: () => {},
      },
      itemPerRow: {
        type: [Number, String],
        default: 4,
      },
      beforeQuery: {
        type: Function,
        default: () => {},
      },
      querySuccess: {
        type: Function,
        default: (val) => val,
      },
      fetchNow: {
        type: Boolean,
        default: true,
      },
      pageOffset: {
        type: Number,
        default: 0,
      },
    },
    emit: ['page-change', 'size-change', 'search', 'selection-change','getSearchData','getTotal'],
    setup(props, { emit }) {
      const {
        apiUrl,
        rowKey,
        option,
        pagination,
        itemPerRow,
        beforeQuery,
        querySuccess,
        fetchNow,
        pageOffset,
      } = props;
      const s_optioned = ref(false);
      const state = reactive({
        s_localOption: [],
        s_list: [],
        s_initSearchInfo: {},
        s_selectedData: {},
        s_searchInfo: {},
      });
      const s_pagination = reactive({
        // 当前页面
        page: 1 - pageOffset,
        // 每页数量
        size: 10,
        // 总页数
        total: 0,
        // 请求标志位
        loading: false,
        ...pagination,
      });
      const { $http: http } = getCurrentInstance().appContext.config.globalProperties;
      let searchTable = ref(null);

      // Watch & Computed
      watch(
        () => option,
        () => {
          s_initSearch();
        },
      );
      watch(
        () => s_pagination.page,
        () => {
          getList();
        },
      );
      watch(
        () => s_pagination.size,
        () => {
          if (s_pagination.page == firstPage) {
            getList();
          } else {
            s_pagination['page'] = firstPage;
          }
        },
      );

      const firstPage = computed(() => 1 - pageOffset);

      // Methods
      /**
       * 初始化搜索组件, 所有的组件字段都是空值
       */
      const s_initSearch = () => {
        // 防止多次初始化
        if (s_optioned.value) return;

        state.s_localOption = option
          .filter((opt) => opt.name)
          .map((opt) => {
            // 默认值
            state.s_searchInfo[opt.name] = '';
            return opt;
          });

        // 保存初始的状态
        state.s_initSearchInfo = { ...state.s_searchInfo };
        s_optioned.value = true;
      };

      const s_pageChange = (val) => {
        const targetPage = val - pageOffset;
        emit('page-change', targetPage);
        s_pagination['page'] = targetPage;
      };

      const s_sizeChange = (val) => {
        emit('size-change', val);
        s_pagination['size'] = val;
      };
      /**
       * 重置搜索条件
       */
      const s_resetSearchInfo = () => {
        state.s_searchInfo = { ...state.s_initSearchInfo };
      };
      /**
       * 搜索事件
       */
      const s_fetchData = () => {
        
        emit('search', state.s_searchInfo);
        s_searchHandler(state.s_searchInfo);
      };
      /**
       * 搜索
       */
      const s_searchHandler = (data) => {
        // 回到第一页
        s_pagination['page'] = 1;
        getList();
      };

      /**
       * 选择数据的回调
       */
      const s_selectChange = (val) => {
        emit('selection-change', val);
        state.s_selectedData = [...val];
      };
      /**
       * 更新数据
       * public
       */
      const updateSearchInfo = (key, value) => {
        // key-value覆盖
        if (typeof key === 'string') {
          state.s_searchInfo[key] = value;
        }
        // 传值覆盖
        if (typeof key === 'object') {
          state.s_searchInfo = {
            ...state.s_searchInfo,
            ...key,
          };
        }
      };

      /**
       * 获取数据
       */
      const getList = () => {
        beforeQuery({
          searchInfo: state.s_searchInfo,
        });

        if (!apiUrl) return;

        s_pagination['loading'] = true;

        const { page, size } = s_pagination;
        const listQueryParams = {
          ...state.s_searchInfo,
          page,
          size,
        };

        emit('getSearchData',listQueryParams)

        http
          .get(apiUrl, {
            params: listQueryParams,
          })
          .then((res) => {
            const { page, pageSize, rows, total } = res;
            if (querySuccess) {
              state.s_list = querySuccess(rows);
            } else {
              state.s_list = rows;
            }
            s_pagination['total'] = total;

            emit('getTotal',s_pagination['total'])
          })
          .catch(() => {})
          .finally(() => {
            // 取消loading
            s_pagination['loading'] = false;
          });
      };

      // Life Circle
      onMounted(() => {
        s_initSearch();
        if (fetchNow && getList) {
          getList();
        }
      });

      return {
        s_optioned,
        s_pagination,
        state,
        searchTable,
        s_initSearch,
        s_pageChange,
        s_sizeChange,
        s_resetSearchInfo,
        s_fetchData,
        s_searchHandler,
        s_selectChange,
        updateSearchInfo,
        getList,
      };
    },
  };
  // Life Circle
  onMounted(() => {
    s_initSearch();
    if (s_paginationGetImmediately && getList) {
      getList();
    }
    console.log(searchTable)
  });
</script>

<style lang="less">
  .zeesuu-search-list {
    .search-box {
      padding: 15px 0;

      .el-date-editor {
        width: 100%;
      }
    }

    .search-input-box {
      display: flex;
      flex-wrap: wrap;
      align-items: flex-start;
      align-content: space-around;
      flex-flow: row wrap;
      .el-row {
        width: 100%;
      }
    }

    .btn-before {
      margin-right: 10px;
    }

    .tab-before {
      font-size: 12px;
      padding-bottom: 10px;
    }

    .el-button + .btn-after {
      margin-left: 10px;
    }

    .search-btn-box {
      margin: 10px 0;
      box-sizing: border-box;
      display: flex;
    }

    .el-pagination {
      padding: 2px 20px;
      margin-top: 10px;
      text-align: right;
    }

    .search-item {
      display: flex;
      align-items: center;

      .label-box {
        min-width: 70px;
        display: inline-block;
      }

      label {
        font-weight: normal;
      }
    }
  }
</style>
